package com.ss.spider.security.auth.ajax;

import com.ss.spider.security.entity.UserTokenRequest;
import com.ss.spider.security.exception.NotSupportedException;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.util.StringUtils;


public class AjaxLoginProcessingFilter extends AbstractAuthenticationProcessingFilter {

    private static Logger logger = LoggerFactory.getLogger(AjaxLoginProcessingFilter.class);


    private final AuthenticationSuccessHandler successHandler;


    private final AuthenticationFailureHandler failureHandler;


    private final ObjectMapper objectMapper;


    public AjaxLoginProcessingFilter(String defaultProcessUrl, AuthenticationSuccessHandler successHandler, AuthenticationFailureHandler failureHandler, ObjectMapper objectMapper) {
        super(defaultProcessUrl);
        this.successHandler = successHandler;
        this.failureHandler = failureHandler;
        this.objectMapper = objectMapper;
    }


    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        if (!HttpMethod.POST.name().equals(request.getMethod())) {
            if (logger.isDebugEnabled()) {
                logger.debug("Authentication method not supported. Request method: " + request.getMethod());
            }

            throw new NotSupportedException("Authentication method not supported");
        }


        UserTokenRequest userReq = (UserTokenRequest) this.objectMapper.readValue(request.getReader(), UserTokenRequest.class);
        if (StringUtils.isEmpty(userReq.getUsername()) || StringUtils.isEmpty(userReq.getPassword())) {
            throw new AuthenticationServiceException("Username or Password not provided");
        }


        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(userReq.getUsername(), userReq.getPassword());
        return getAuthenticationManager().authenticate(token);
    }


    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        this.successHandler.onAuthenticationSuccess(request, response, authResult);
    }


    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        SecurityContextHolder.clearContext();
        this.failureHandler.onAuthenticationFailure(request, response, failed);
    }

}
